local pb = require 'pb'

---@class Proto
local Proto = {}

local protoCSCmd
local protoSCCmd
local decodeed = true;

local default_cache_tb = {}
local __decode = pb.decode

local __G_ERROR_TRACK = function(err)
    Debug.Log("*ERROR:{0}", err)
end

--打印时忽略列表中的协议
Proto.ignore = {
    ["PingRequest"] = true,
    ["com.bochsler.protocol.PingResponse"] = true,
    ["WorldPlayerMove"] = true,
    ["com.bochsler.protocol.WorldPlayerMove"] = true,
    ["ChangeHeadRequest"] = true,
    ["com.bochsler.protocol.ChangeHeadResponse"] = true,
}

local decode = function(sn, typename, buffer)
    if nil ~= buffer then
        local ret = __decode(typename, buffer);

        if Proto.ignore[typename] == nil then
            Debug.Log(string.format("decode:%s <color=#ffff00>%s</color> | dataStruct:%s", sn, typename,
                "L_Cjson.encode(ret)"))
        end

        if false == ret then
            Debug.Log("err" .. "\t" .. typename);
            decodeed = false;
            return false;
        end

        return ret
    end
    --default data
    local def = default_cache_tb[typename];
    if nil == def then
        def = pb.default(typename, {});
        default_cache_tb[typename] = def;
    end
    return def;
end

function Proto:initialize(options)
    protoCSCmd = options.CSCmd
    protoSCCmd = options.SCCmd
    -- pb.load(options.bytes)
    CS.ResMgr.Instance:LoadRes("bytes_asset", "protocal", function(obj)
        pb.load(obj.bytes)
    end, 0)
end

function Proto:encode(type, msg, data)
    local p = nil
    local msgId = nil
    local errorMsg = nil

    if type == "cs" then
        local name = protoCSCmd.msg[msg]
        if name == nil then
            Debug.Log("serialize cmd is null > " .. msg)
        else
            p, errorMsg = pb.encode(name, data)
            msgId = protoCSCmd.msgToId[msg]
        end
    elseif type == "sc" then
        local name = protoSCCmd.msg[msg]
        if name == nil then
            Debug.Log("serialize cmd is null > " .. msg)
        else
            p, errorMsg = pb.encode(name, data)
            msgId = protoCSCmd.msgToId[msg]
        end
    else
        Debug.Log("serialize type is error > " .. type)
    end
    if errorMsg then
        Debug.Log("serialize type is error > " .. msg .. "  " .. errorMsg)
    end
    return p, msgId
end

function Proto:decode(type, sn, cmd, data)
    local p = nil
    local ok, err = xpcall(function()
        if type == "cs" then
            local name = protoCSCmd.id[cmd]
            if name == nil then
                Debug.LogError("serialize cmd is null > {0}", cmd)
            else
                p = decode(sn, name, data)
            end
        elseif type == "sc" then
            local name = protoSCCmd.id[cmd]
            if name == nil then
                Debug.LogError("serialize cmd is null > {0}", cmd)
            else
                p = decode(sn, name, data)
            end
        else
            Debug.LogError("serialize type is error > {0}", type)
        end
    end, function()
        if __G_ERROR_TRACK then
            __G_ERROR_TRACK(cmd)
        else
            Debug.LogError("msg decode error! cmd={0}", cmd)
        end
    end, 33)

    if not ok then
        if __G_ERROR_TRACK then
            __G_ERROR_TRACK(cmd)
        else
            Debug.LogError("msg decode error! cmd={0}", cmd)
        end
    else
        return p
    end
end

function Proto:getCSCmd(msg)
    return protoCSCmd.msgToId[msg]
end

function Proto:getSCCmd(msg)
    return protoSCCmd.msgToId[msg]
end

return Proto
